# 确保加载 System.Windows.Forms 程序集
Add-Type -AssemblyName 'System.Windows.Forms'

Add-Type -ReferencedAssemblies 'System.Windows.Forms' -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public static class KeyboardInterceptor
{
    private const int WH_KEYBOARD_LL = 13;

    private const int WM_KEYDOWN    = 0x0100;
    private const int WM_KEYUP      = 0x0101;
    private const int WM_SYSKEYDOWN = 0x0104;
    private const int WM_SYSKEYUP   = 0x0105;

    private const int VK_CAPITAL = 0x14;
    private const int VK_ESCAPE  = 0x1B;

    private static IntPtr hookID = IntPtr.Zero;

    private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

    private static LowLevelKeyboardProc proc = HookCallback;

    [StructLayout(LayoutKind.Sequential)]
    private struct KBDLLHOOKSTRUCT
    {
        public int vkCode;
        public int scanCode;
        public int flags;
        public int time;
        public UIntPtr dwExtraInfo;
    }

    [DllImport("user32.dll", SetLastError=true)]
    private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll", SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool UnhookWindowsHookEx(IntPtr hhk);

    [DllImport("user32.dll", SetLastError=true)]
    private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

    [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
    private static extern IntPtr GetModuleHandle(string lpModuleName);

    [DllImport("user32.dll")]
    private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);

    private const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
    private const uint KEYEVENTF_KEYUP       = 0x0002;

    public static void SetHook()
    {
        if (hookID == IntPtr.Zero)
        {
            proc = HookCallback;

            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                hookID = SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
                if (hookID == IntPtr.Zero)
                {
                    throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
                }
                else
                {
                    Console.WriteLine("键盘钩子设置成功！");
                }
            }
        }
    }

    public static void Unhook()
    {
        if (hookID != IntPtr.Zero)
        {
            UnhookWindowsHookEx(hookID);
            Console.WriteLine("键盘钩子已移除！");
            hookID = IntPtr.Zero;
        }
    }

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0)
        {
            int wParamInt = wParam.ToInt32();

            if (wParamInt == WM_KEYDOWN || wParamInt == WM_SYSKEYDOWN || wParamInt == WM_KEYUP || wParamInt == WM_SYSKEYUP)
            {
                KBDLLHOOKSTRUCT kbStruct = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));

                if (kbStruct.vkCode == VK_CAPITAL)
                {
                    // 屏蔽 CapsLock 键
                    // 模拟 Esc 键的按下和释放
                    if (wParamInt == WM_KEYDOWN || wParamInt == WM_SYSKEYDOWN)
                    {
                        keybd_event((byte)VK_ESCAPE, 0, KEYEVENTF_EXTENDEDKEY, UIntPtr.Zero);
                    }
                    else if (wParamInt == WM_KEYUP || wParamInt == WM_SYSKEYUP)
                    {
                        keybd_event((byte)VK_ESCAPE, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, UIntPtr.Zero);
                    }
                    // 返回 1 表示我们已处理该消息，阻止 CapsLock 原有功能
                    return (IntPtr)1;
                }
            }
        }
        return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
    }

    public static void Start()
    {
        Console.WriteLine("开始键盘监听...");
        Application.Run();
    }

    public static void Stop()
    {
        Application.Exit();
    }
}
"@

# 开始设置钩子
[KeyboardInterceptor]::SetHook()

Write-Host "CapsLock 已被映射为 Esc 键。按 Ctrl+C 停止。" -ForegroundColor Green

try {
    [KeyboardInterceptor]::Start()
}
finally {
    # 当脚本终止时，移除钩子
    [KeyboardInterceptor]::Unhook()
}
